﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Hockey.Shared;

using Microsoft.Practices.Prism.Events;

namespace Hockey.UILayer.Controls
{
    /// <summary>
    /// Interaction logic for CompassControl.xaml
    /// </summary>
    public partial class CompassControl : UserControl
    {
        private IBoard _board;
        private IEventAggregator _events;
        private int _inputBlockCounter = 0;
        

        public CompassControl(IBoard board, IEventAggregator events)
        {
            InitializeComponent();

            if (board == null)
                throw new ArgumentNullException("Board");
            _board = board;

            if (events == null)
                throw new ArgumentNullException("Event Aggregator");
            _events = events;

            // refresh buttons
            RefreshButtons();

            // add button handler
            AddHandler(Button.ClickEvent, new RoutedEventHandler(ArrowButtonClicked));

            // register events
            _events.GetEvent<BoardChanged>().Subscribe((obj) => { RefreshButtons(); }, true);
            _events.GetEvent<PressCompassButton>().Subscribe((dir) => { ChangePressCompassButton(dir, true); }, ThreadOption.UIThread, true);
            _events.GetEvent<UnpressCompassButton>().Subscribe((dir) => { ChangePressCompassButton(dir, false); }, ThreadOption.UIThread, true);
            _events.GetEvent<SetInputBlocking>().Subscribe((blocked) =>
            {
                if (blocked)
                    _inputBlockCounter++;
                else
                    _inputBlockCounter--;
            }, true);

        }

        /// <summary>
        /// Refreshes the enabled state by valid move directions
        /// </summary>
        private void RefreshButtons()
        {
            uxTopLeft.IsEnabled = _board.CanPlayInThisDirection(eMoveDirection.NorthWest);
            uxTop.IsEnabled = _board.CanPlayInThisDirection(eMoveDirection.North);
            uxTopRight.IsEnabled = _board.CanPlayInThisDirection(eMoveDirection.NorthEast);
            uxLeft.IsEnabled = _board.CanPlayInThisDirection(eMoveDirection.West);
            uxRight.IsEnabled = _board.CanPlayInThisDirection(eMoveDirection.East);
            uxBottomLeft.IsEnabled = _board.CanPlayInThisDirection(eMoveDirection.SouthWest);
            uxBottom.IsEnabled = _board.CanPlayInThisDirection(eMoveDirection.South);
            uxBottomRight.IsEnabled = _board.CanPlayInThisDirection(eMoveDirection.SouthEast);    
        }

        /// <summary>
        /// Change the press state of compass button
        /// </summary>
        private void ChangePressCompassButton(eMoveDirection dir, bool isPressed)
        {
            // get button by direction
            ArrowButton but = MapButtonByDirection(dir);
            if (but == null)
                return;
            
            // if not button enabled, exit - keyboard handler cannot check validity of the move
            if (but.IsEnabled == false)
                return;

            // change press state
            but.SetPressed(isPressed);
        }

        /// <summary>
        /// Returns button by direction
        /// </summary>
        private ArrowButton MapButtonByDirection(eMoveDirection dir)
        {
            switch (dir)
            {
                case eMoveDirection.NorthEast:
                    return uxTopRight;
                case eMoveDirection.North:
                    return uxTop;
                case eMoveDirection.NorthWest:
                    return uxTopLeft;
                case eMoveDirection.East:
                    return uxRight;
                case eMoveDirection.West:
                    return uxLeft;
                case eMoveDirection.SouthEast:
                    return uxBottomRight;
                case eMoveDirection.South:
                    return uxBottom;
                case eMoveDirection.SouthWest:
                    return uxBottomLeft;
                default:
                    return null;
            }
        }

        /// <summary>
        /// Handler for arrow button click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ArrowButtonClicked(object sender, RoutedEventArgs e)
        {
            // check input blocked
            if (_inputBlockCounter > 0)
                return;

            eMoveDirection dir;

            // complete the movement direction
            if (e.OriginalSource == uxTopLeft)
            {
                dir = eMoveDirection.NorthWest;
            }
            else if (e.OriginalSource == uxTop)
            {
                dir = eMoveDirection.North;
            }
            else if (e.OriginalSource == uxTopRight)
            {
                dir = eMoveDirection.NorthEast;
            }
            else if (e.OriginalSource == uxLeft)
            {
                dir = eMoveDirection.West;
            }
            else if (e.OriginalSource == uxRight)
            {
                dir = eMoveDirection.East;
            }
            else if (e.OriginalSource == uxBottomLeft)
            {
                dir = eMoveDirection.SouthWest;
            }
            else if (e.OriginalSource == uxBottom)
            {
                dir = eMoveDirection.South;
            }
            else if (e.OriginalSource == uxBottomRight)
            {
                dir = eMoveDirection.SouthEast;
            }
            else
            {
                Debug.Assert(false);
                throw new ApplicationException("Uknown button pressed.");
            }

            // fire the move step
            _events.GetEvent<MoveStepFired>().Publish(dir);

            e.Handled = true;
        }
    }
}
